<?php

declare(strict_types=1);
/*
 * This file is part of Leonsw.
 *
 * @link     https://leonsw.com
 * @document https://docs.leonsw.com
 * @contact  leonsw.com@gmail.com
 * @license  https://leonsw.com/LICENSE
 */
namespace App\Services\Tools;

use App\Exceptions\BasicException;
use Illuminate\Support\Collection;

class Joinpay
{
    protected $baseUrl = 'https://www.joinpay.com';

    protected function build(array $order)
    {
        $order = array_merge([
            'p0_Version' => '1.0',
            'p1_MerchantNo' => env('JOINPAY_MCH_ID'),
            'p4_Cur' => '1',
            'p9_NotifyUrl' => env('JOINPAY_NOTIFY_URL'),
        ], $order);
        $order['hmac'] = $this->signature($order);
        return $order;
    }

    public function wechatApp(array $order)
    {
        $order = array_merge([
            'q1_FrpCode' => 'WEIXIN_APP3',
//            'qa_TradeMerchantNo' => env('JOINPAY_TRADE_ID'),
            'qa_TradeMerchantNo' => app('model_config')->getValue('JOINPAY_WECHAT_TARDE_ID'),
            'q7_AppId' => app('model_config')->getValue('JOINPAY_WECHAT_APP_ID'), // APP
        ], $order);

        $response = $this->submit('/trade/uniPayApi.action', $this->build($order));
        return $response;
    }

    public function wechatH5(array $order)
    {
        $order = array_merge([
            'q1_FrpCode' => 'WEIXIN_H5_PLUS',
//            'qa_TradeMerchantNo' => env('JOINPAY_TRADE_ID'),
            'qa_TradeMerchantNo' => app('model_config')->getValue('JOINPAY_WECHAT_TARDE_ID'),
            'q7_AppId' => app('model_config')->getValue('JOINPAY_WECHAT_APP_ID'), // H5
        ], $order);

        $response = $this->submit('/trade/uniPayApi.action', $this->build($order));
        return $response;
    }

    public function alipayH5(array $order)
    {
        $order = array_merge([
            'q1_FrpCode' => 'ALIPAY_H5',
            'qa_TradeMerchantNo' => env('JOINPAY_ALIPAY_TRADE_ID')
//            'qa_TradeMerchantNo' => app('model_config')->getValue('JOINPAY_ALIPAY_TARDE_ID'),
        ], $order);
        $response = $this->submit('/trade/uniPayApi.action', $this->build($order));
        $url = $this->match('/href=[\'|"](.*)[\'|"]/', $response->get('rc_Result'));
        return new Collection(['code_url' => $url, 'ra_Code' => $response->get('ra_Code'), 'rb_CodeMsg' => $response->get('rb_CodeMsg')]);
    }


    public function match($pattern, $subject)
    {
        preg_match($pattern, $subject, $matches);
        if (! $matches) {
            return '';
        }
        return $matches[1] ?? $matches[0];
    }

    public function signature(array $body): string
    {
        ksort($body);
        $signContent = implode('', $body);
        return md5($signContent . env('JOINPAY_SECRET'));
    }

    public function verify(array $data): bool
    {
        $sign = $data['hmac'] ?? '';
        unset($data['hmac']);
        return $this->signature($data) === $sign;
    }

    public function callback($data)
    {
        $data['ra_PayTime'] = urldecode($data['ra_PayTime']);
        $data['rb_DealTime'] = urldecode($data['rb_DealTime']);
        if ($this->verify($data)) {
            return new Collection($data);
        }
        return new Collection([]);
    }

    protected function submit(string $url, array $body)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($curl, CURLOPT_URL, $this->baseUrl . $url);
        curl_setopt($curl, CURLOPT_FAILONERROR, false);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
        curl_setopt($curl, CURLOPT_HEADER, false);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($curl);
        if ((curl_errno($curl) != 0)) {
            $message = 'CURL ERROR NO:' . curl_errno($curl) . ', MESSAGE:' . curl_error($curl);
            throw new BasicException(0, $message);
        }
        $data = json_decode($response);
        return new Collection($data);
    }

}